﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using System.Xml.Xsl;
using ConsoleXmlParser;

public partial class _Default : System.Web.UI.Page
{
	private const string MAIN_DIRECTORY = @"~\";
	private const string XMLNS_PATTERN = "(xmlns=\")(.)+(\")";
	private const string XMLNS_REPLACEMENT = "";
	private const string XML_FILE_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
	private const string XML_EXTENSION = ".xml";
	private const string TAG_PATTERN = @"(?<tag>(<.+?/?>))";

	private const string FILE_NAME_RELEASE_NOTES = "Release-Notes.xml";
	private const string FILE_NAME_LATEST_INTERNAL_BUILD = "Latest-Internal-build.html";
	private const string FILE_PATH_TEAM_PULSE_FILE_WITH_REMOVED_XMLNS = "TeamPulse-File-Removed-Xmlns.xml";
	private const string FILE_PATH_SIMPLIFIED_TEAM_PULSE_FILE = "Simplified-TeamPulse-File.xml";
	private const string FILE_PATH_TEMPLATE_RELEASE_NOTES = "Template-Release-Notes.xsl";
	private const string FILE_PATH_TEMPLATE_LATEST_INTERNAL_BUILD = "Template-Latest-Internal-Build.xsl";

	private const string MESSAGE_FILE_DOESNT_EXIST = "The file you uploaded does NOT exist!";
	private const string MESSAGE_FILE_CANNOT_BE_LOADED = "The file you specified cannot be loaded!";
	private const string MESSAGE_XMLNS_CANNOT_BE_REMOVED = "There was a problem with removing the xmlns tag from the input file!";
	private const string MESSAGE_INCORRECT_FILE_STRUCTURE =
		"The specified file doesn't match the default excelXML structure from TeamPulse! " +
		"Check for incorrect opened or closed tags in bug's or story's text or empty paragraphs in them. " +
		"Please contact Stamo Gochev from ASP.NET TEAM 2";
	private const string CSV_EXTENSION = ".csv";

	protected void Page_Load(object sender, EventArgs e)
	{
		if (Page.IsPostBack)
		{
			this.LabelFileName.Text = "";
		}
	}

	protected void ButtonConvertToReleaseNotes_Click(object sender, EventArgs e)
	{
		this.LabelFileName.Text = "";
		Convert(FILE_PATH_TEMPLATE_RELEASE_NOTES, FILE_NAME_RELEASE_NOTES);
	}

	protected void ButtonConvertToLatestInternalBuild_Click(object sender, EventArgs e)
	{
		this.LabelFileName.Text = "";
		Convert(FILE_PATH_TEMPLATE_LATEST_INTERNAL_BUILD, FILE_NAME_LATEST_INTERNAL_BUILD);
	}

	//protected void ButtonConvertCSVToReleaseNotes_Click(object sender, EventArgs e)
	//{
	//	this.LabelFileName.Text = "stamo";
	//	this.LabelFileName.Visible = true;
	//	Convert(FILE_PATH_TEMPLATE_RELEASE_NOTES, FILE_NAME_RELEASE_NOTES);
	//}

	//protected void ButtonConvertCSVToLatestInternalBuild_Click(object sender, EventArgs e)
	//{
	//	this.LabelFileName.Text = "";
	//	Convert(FILE_PATH_TEMPLATE_LATEST_INTERNAL_BUILD, FILE_NAME_LATEST_INTERNAL_BUILD);
	//}

	private void Convert(string templateFileName, string parsedFileName)
	{
		if (FileUpload.HasFile)
		{
			string fileExtension = Path.GetExtension(FileUpload.FileName);

			if (fileExtension == XML_EXTENSION || fileExtension == CSV_EXTENSION)
			{
				try
				{
					string filePathUploadedTeamPulseFile = Server.MapPath(MAIN_DIRECTORY + FileUpload.FileName);
					string filePathRemovedXmlns = Server.MapPath(MAIN_DIRECTORY + FILE_PATH_TEAM_PULSE_FILE_WITH_REMOVED_XMLNS);
					string filePathSimplifiedXmlFile = Server.MapPath(MAIN_DIRECTORY + FILE_PATH_SIMPLIFIED_TEAM_PULSE_FILE);
					string filePathParsedHtml = Server.MapPath(MAIN_DIRECTORY + parsedFileName);
					string filePathParsingTemplate = Server.MapPath(MAIN_DIRECTORY + templateFileName);

					FileUpload.SaveAs(filePathUploadedTeamPulseFile);
					LabelFileName.Text = "XML file successfully parsed!" + "<br>" + "File name: " +
						FileUpload.PostedFile.FileName + "<br>" +
						FileUpload.PostedFile.ContentLength + " kb<br>" + "Content type: " +
						FileUpload.PostedFile.ContentType;

					Parse(filePathUploadedTeamPulseFile, filePathRemovedXmlns,
						filePathSimplifiedXmlFile, filePathParsedHtml, filePathParsingTemplate, fileExtension);

					CreateFileForDownloading(filePathRemovedXmlns, parsedFileName);
				}
				catch (Exception ex)
				{
					LabelFileName.Text = "ERROR: " + ex.Message.ToString();
				}
			}
			else
			{
				LabelFileName.Text = "Only .csv and .xml files are allowed to be parsed!";
			}
		}
		else
		{
			LabelFileName.Text = "You have not specified a file!";
		}
	}

	private void CreateFileForDownloading(string filePathRemovedXmlns, string outputFile)
	{
		StreamWriter writer = new StreamWriter(filePathRemovedXmlns);
		FileInfo resultFile = new FileInfo(Server.MapPath(MAIN_DIRECTORY + outputFile));
		Response.Clear();
		Response.AddHeader("content-disposition", "attachment;filename=" + outputFile);
		Response.ContentType = "text/html";
		writer.Close();
		Response.TransmitFile(Server.MapPath(MAIN_DIRECTORY + outputFile), 0, resultFile.Length);
		Response.Flush();
		Response.End();
	}

	private static void Parse(string filePathTeamPulseXmlFile, string filePathRemovedXmlns,
		string filePathSimplifiedXmlFile, string filePathParsedHtml, string filePathParsingTemplate, string fileExtension)
	{
		CreateSimplifiedTeamPulseFile(filePathTeamPulseXmlFile, filePathRemovedXmlns, filePathSimplifiedXmlFile, fileExtension);
		ExecuteXSLT(filePathParsingTemplate, filePathSimplifiedXmlFile, filePathParsedHtml);
	}
  
	private static void ExecuteXSLT(string filePathParsingTemplate, string filePathSimplifiedXmlFile, string filePathParsedHtml)
	{
		XslCompiledTransform xsltParser = new XslCompiledTransform();
		xsltParser.Load(filePathParsingTemplate);
		xsltParser.Transform(filePathSimplifiedXmlFile, filePathParsedHtml);
	}

	public static void CreateFileWithRemovedXmlns(string filePathOriginalXmlFile, string filePathRemovedXmlnsFile)
	{
		if (!File.Exists(filePathOriginalXmlFile))
		{
			throw new FileNotFoundException(MESSAGE_FILE_DOESNT_EXIST);
		}

		string textToFind = "xmlns=";

		using (StreamWriter writer = new StreamWriter(filePathRemovedXmlnsFile))
		{
			using (StreamReader reader = File.OpenText(filePathOriginalXmlFile))
			{
				bool isTextFound = false;
				int lineNumber = 0;
				string line = null;
				while ((line = reader.ReadLine()) != null)
				{
					lineNumber++;
					if (line.IndexOf(textToFind) > -1)
					{
						isTextFound = true;
						string replacedLine = Regex.Replace(line, XMLNS_PATTERN, XMLNS_REPLACEMENT);
						writer.WriteLine(replacedLine);
					}
					else
					{
						writer.WriteLine(line);
					}
				}
				if (!isTextFound)
				{
				}
			}
		}
	}

	private static void CreateSimplifiedTeamPulseFile(string filePathOriginalFile, string filePathRemovedXmlns, 
		string filePathSimplifiedXmlFile, string fileExtension)
	{
		if (!File.Exists(filePathOriginalFile))
		{
			throw new FileNotFoundException(MESSAGE_FILE_DOESNT_EXIST);
		}

		if (fileExtension == CSV_EXTENSION)
		{
			CSVParser csvParser = new CSVParser();
			csvParser.Parse(filePathOriginalFile, filePathSimplifiedXmlFile);
		}
		else
		{
			CreateFileWithRemovedXmlns(filePathOriginalFile, filePathRemovedXmlns);
			ProcessXMLFile(filePathRemovedXmlns, filePathSimplifiedXmlFile);
		}
	}

	private static void ProcessXMLFile(string filePathRemovedXmlns, string filePathSimplifiedXmlFile)
	{
		XmlDocument xmlDocument = new XmlDocument();
		try
		{
			xmlDocument.Load(filePathRemovedXmlns);
		}
		catch (Exception e)
		{
			Console.WriteLine(MESSAGE_FILE_CANNOT_BE_LOADED + Environment.NewLine + e.Message);
		}

		string xPathQueryMatchRows = "/Workbook/Worksheet/Table/Row";
		string xPathQueryMatchCells = "Cell";
		XmlNodeList rows = xmlDocument.SelectNodes(xPathQueryMatchRows);
		if (rows.Count == 0)
		{
			throw new Exception(MESSAGE_INCORRECT_FILE_STRUCTURE);
		}

		string previousControlName = null;
		using (StreamWriter writer = new StreamWriter(filePathSimplifiedXmlFile))
		{
			writer.WriteLine(XML_FILE_HEADER);
			writer.WriteLine("<controls>");
			writer.WriteLine("<control>");

			List<string> stories = new List<string>();
			List<string> bugs = new List<string>();

			foreach (XmlNode item in rows)
			{
				XmlNodeList cells = item.SelectNodes(xPathQueryMatchCells);

				string currentElementType = cells[0].InnerText;
				string currentElementText = cells[1].InnerText;
				string currentControlName = cells[2].InnerText;

				string controlNameWithRemovedBackSlashes = GetStrippedName(currentControlName);

				if (previousControlName != controlNameWithRemovedBackSlashes)
				{
					WriteStoriesAndBugs(writer, stories, bugs);
					previousControlName = controlNameWithRemovedBackSlashes;
					writer.WriteLine("<control>");
					string controlNameWithoutRadPrefix = controlNameWithRemovedBackSlashes.Replace("Rad", "");
					writer.WriteLine("<area>" + controlNameWithoutRadPrefix + "</area>");
				}
				AddStoryOrBug(stories, bugs, currentElementType, currentElementText);
			}

			WriteStoriesAndBugs(writer, stories, bugs);
			writer.WriteLine("</controls>");
		}
	}

	private static void AddStoryOrBug(List<string> stories, List<string> bugs, string currentElementType, string currentElementText)
	{
		if (currentElementType == "Bug")
		{
			bugs.Add(currentElementText);
		}
		else
		{
			if (currentElementType == "Story")
			{
				stories.Add(currentElementText);
			}
		}
	}

	private static void WriteStoriesAndBugs(StreamWriter writer, List<string> stories, List<string> bugs)
	{
		if (stories.Count > 0)
		{
			writer.WriteLine("<stories>");
			for (int i = 0; i < stories.Count; i++)
			{
				string finalStoryText = HttpUtility.HtmlEncode(stories[i]);
				writer.WriteLine("<story>" + finalStoryText + "</story>");
			}
			writer.WriteLine("</stories>");
		}
		stories.Clear();

		if (bugs.Count > 0)
		{
			writer.WriteLine("<bugs>");
			for (int i = 0; i < bugs.Count; i++)
			{
				string finalBugText = HttpUtility.HtmlEncode(bugs[i]);
				writer.WriteLine("<bug>" + finalBugText + "</bug>");
			}
			writer.WriteLine("</bugs>");
		}
		bugs.Clear();

		writer.WriteLine("</control>");
	}

	private static string GetStrippedName(string controlName)
	{
		int firstBackSlashPosition = controlName.IndexOf("/");
		bool isStripped = false;
		string strippedName = null;
		if (firstBackSlashPosition > 0)
		{
			int secondBackSlashPosition = controlName.IndexOf("/", firstBackSlashPosition + 1);
			if (secondBackSlashPosition > 0)
			{
				strippedName = controlName.Substring(firstBackSlashPosition + 1, secondBackSlashPosition - 5).Trim();
			}
			else
			{
				strippedName = controlName.Substring(firstBackSlashPosition + 1).Trim();
			}
			isStripped = true;
		}

		if (isStripped == true)
		{
			return strippedName;
		}

		return controlName;
	}
}